﻿using System.Collections.ObjectModel;
using System.Text.Json.Serialization;

namespace LightCAD.Core
{


    //[JsonConverter(typeof(ElementStyleConverter))]
    public class ElementStyle
    {
        private string _key;

        public string Key
        {
            get
            {
                if (_key == null)
                {
                    _key = ToString();
                }
                return _key;
            }
            set
            {
                _key = value;
                Parse(_key, this);
            }
        }
        [JsonIgnore]
        internal bool IsUsed { get; set; } = true;
        [JsonIgnore]
        public Layer Layer { get; internal set; }
        [JsonIgnore]
        public ValueFrom ColorFrom { get; internal set; }
        [JsonIgnore]
        public string Color { get; internal set; }
        [JsonIgnore]
        public LineType LineType { get; internal set; }
        [JsonIgnore]
        public ValueFrom LineTypeFrom { get; internal set; }
        [JsonIgnore]
        public double LineTypeScale { get; internal set; }
        [JsonIgnore]
        public LineWeight LineWeight { get; internal set; }
        [JsonIgnore]
        public ValueFrom TransparencyFrom { get; internal set; }
        [JsonIgnore]
        public double Transparency { get; internal set; }
        [JsonIgnore]
        public string PlotStyleName { get; internal set; }
        //public string TextStyleName { get; set; }
        //public string FillStyleName { get; set; }

        public ElementStyle() { }

        public ElementStyle(
            Layer layer = null,
            ValueFrom colorFrom = ValueFrom.ByLayer,
            string color = null,
            ValueFrom lineTypeFrom = ValueFrom.ByLayer,
            LineType lineType = null,
            double lineTypeScale = 0,
            LineWeight lineWeight = LineWeight.ByLayer,
            ValueFrom transparencyFrom = ValueFrom.ByLayer,
            double transparency = 0,
            string plotStyleName = null)
        {
            this.Layer = layer;
            this.ColorFrom = colorFrom;
            this.Color = color;
            this.LineTypeFrom = lineTypeFrom;
            this.LineType = lineType;
            this.LineTypeScale = lineTypeScale;
            this.LineWeight = lineWeight;
            this.TransparencyFrom = transparencyFrom;
            this.Transparency = transparency;
            this.PlotStyleName = plotStyleName;

        }
        public ElementStyle Clone(
            Layer? layer = null,
            ValueFrom? colorFrom = null,
            string? color = null,
            ValueFrom? lineTypeFrom = null,
            LineType? lineType = null,
            double? lineTypeScale = null,
            LineWeight? lineWeight = null,
            ValueFrom? transparencyFrom = null,
            double? transparency = null,
            string? plotStyleName = null
            )
        {
            var newStyle = new ElementStyle();
            if (layer != null)
                newStyle.Layer = layer;
            else
                newStyle.Layer = Layer;

            if (colorFrom != null)
                newStyle.ColorFrom = colorFrom.Value;
            else
                newStyle.ColorFrom = ColorFrom;

            if (color != null)
                newStyle.Color = color;
            else
                newStyle.Color = Color;

            if (lineTypeFrom != null)
                newStyle.LineTypeFrom = lineTypeFrom.Value;
            else
                newStyle.LineTypeFrom = LineTypeFrom;

            if (lineType != null)
                newStyle.LineType = lineType;
            else
                newStyle.LineType = LineType;


            if (lineTypeScale != null)
                newStyle.LineTypeScale = lineTypeScale.Value;
            else
                newStyle.LineTypeScale = LineTypeScale;


            if (lineWeight != null)
                newStyle.LineWeight = lineWeight.Value;
            else
                newStyle.LineWeight = LineWeight;

            if (transparencyFrom != null)
                newStyle.TransparencyFrom = transparencyFrom.Value;
            else
                newStyle.TransparencyFrom = TransparencyFrom;

            if (transparency != null)
                newStyle.Transparency = transparency.Value;
            else
                newStyle.Transparency = Transparency;

            if (plotStyleName != null)
                newStyle.PlotStyleName = plotStyleName;
            else
                newStyle.PlotStyleName = PlotStyleName;

            return newStyle;
        }

        public override string ToString()
        {
            return $"{(this.Layer == null ? null : this.Layer.Name)}"
                  + $"|{(ColorFrom == ValueFrom.BySelf ? this.Color : ColorFrom.ToString())}"
                  + $"|{(LineTypeFrom == ValueFrom.BySelf ? (this.LineType == null ? null : this.LineType.Name) : LineTypeFrom.ToString())}"
                  + $"|{LineTypeScale}"
                  + $"|{LineWeight}"
                  + $"|{(TransparencyFrom == ValueFrom.BySelf ? this.Transparency : TransparencyFrom.ToString())}"
                  + $"|{PlotStyleName}";
            //+ $"-{TextStyleName}"
            //+ $"-{FillStyleName}";
        }


        public static ElementStyle Parse(string str, ElementStyle style = null)
        {
            if (style == null)
                style = new ElementStyle();
            if (string.IsNullOrWhiteSpace(str))
                return style;
            else
            {
                var parts = str.Split('|');

                var layerName = parts[0];
                if (LcDocument.Current != null && layerName != null)
                {
                    style.Layer = new Layer { Name = layerName };
                }

                var color = parts[1];
                if (color == nameof(ValueFrom.ByLayer) || color == nameof(ValueFrom.ByBlock))
                {
                    style.ColorFrom = (ValueFrom)Enum.Parse(typeof(ValueFrom), color);
                }
                else
                {
                    style.ColorFrom = ValueFrom.BySelf;
                    style.Color = color;
                }

                var lineType = parts[2];
                if (lineType == nameof(ValueFrom.ByLayer) || lineType == nameof(ValueFrom.ByBlock))
                {
                    style.LineTypeFrom = (ValueFrom)Enum.Parse(typeof(ValueFrom), lineType);
                }
                else
                {
                    style.LineTypeFrom = ValueFrom.BySelf;
                    style.LineType = new LineType { Name = lineType };
                }

                var lineTypeScale = parts[3];
                style.LineTypeScale = double.Parse(lineTypeScale);

                var lineWeight = parts[4];
                style.LineWeight = (LineWeight)Enum.Parse(typeof(LineWeight), lineWeight);


                var transparency = parts[5];
                if (transparency == nameof(ValueFrom.ByLayer) || transparency == nameof(ValueFrom.ByBlock))
                {
                    style.TransparencyFrom = (ValueFrom)Enum.Parse(typeof(ValueFrom), transparency);
                }
                else
                {
                    style.TransparencyFrom = ValueFrom.BySelf;
                    style.Transparency = double.Parse(transparency);
                }

                var plotStyleName = parts[6];
                style.PlotStyleName = plotStyleName;

                return style;
            }
        }
    }

    public class ElementStyleCollction : KeyedCollection<string, ElementStyle>
    {
        protected override string GetKeyForItem(ElementStyle item)
        {
            return item.Key;
        }
    }

    public class ElementStyleManager
    {
        public LcDocument Document { get; private set; }

        public bool FireChangedEvent { get; set; }
        public ElementStyleManager(LcDocument document)
        {
            this.Document = document;
        }

        public ElementStyle GetDefault()
        {
            return new ElementStyle();
        }

        public void SetStyle(Element element, ElementStyle style)
        {
            var doc = this.Document;
            if (doc.Styles == null)
            {
                doc.Styles = new ElementStyleCollction();
            }
            if (!doc.Styles.Contains(style.Key))
            {
                doc.Styles.Add(style);
            }
            element.SetStyle(doc.Styles[style.Key], FireChangedEvent);
        }

    }
}